#pragma once

#include <cmath>
#include "gtest/gtest.h"
#include "DataStructure/Common/Constant.h"
#include "../Gauss3DPenta6.h"

using SG::DataStructure::Common::Real;
using SG::DataStructure::Common::TOLERANCE;
using SG::FEMSolver::Element::Gauss3DPenta6;

class Gauss3DPenta6Test : public ::testing::Test
{
public:
    void SetUp () override
    {
        m_integForm = Gauss3DPenta6 ();
    }
protected:
    Gauss3DPenta6 m_integForm;
};

TEST_F (Gauss3DPenta6Test, GetPointSize)
{
    ASSERT_TRUE (6 == m_integForm.GetPointSize ());
}

TEST_F (Gauss3DPenta6Test, GetPoint)
{
    // Test data
    auto point = m_integForm.GetPoint (0);

    // Target data
    const Real xa{2.0 / 3.0};
    const Real xb{1.0 / 6.0};
    const Real xc{sqrt (3.0) / 3.0};

    // Check Point 1
    ASSERT_NEAR (point.m_weight, 1.0 / 6.0, TOLERANCE);
    ASSERT_NEAR (point.m_x,  xa, TOLERANCE);
    ASSERT_NEAR (point.m_y,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_z, -xc, TOLERANCE);

    // Check Point 2
    point = m_integForm.GetPoint (1);
    ASSERT_NEAR (point.m_weight, 1.0 / 6.0, TOLERANCE);
    ASSERT_NEAR (point.m_x,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_y,  xa, TOLERANCE);
    ASSERT_NEAR (point.m_z, -xc, TOLERANCE);

    // Check Point 3
    point = m_integForm.GetPoint (2);
    ASSERT_NEAR (point.m_weight, 1.0 / 6.0, TOLERANCE);
    ASSERT_NEAR (point.m_x,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_y,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_z, -xc, TOLERANCE);

    // Check Point 4
    point = m_integForm.GetPoint (3);
    ASSERT_NEAR (point.m_weight, 1.0 / 6.0, TOLERANCE);
    ASSERT_NEAR (point.m_x,  xa, TOLERANCE);
    ASSERT_NEAR (point.m_y,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_z,  xc, TOLERANCE);

    // Check Point 5
    point = m_integForm.GetPoint (4);
    ASSERT_NEAR (point.m_weight, 1.0 / 6.0, TOLERANCE);
    ASSERT_NEAR (point.m_x,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_y,  xa, TOLERANCE);
    ASSERT_NEAR (point.m_z,  xc, TOLERANCE);

    // Check Point 6
    point = m_integForm.GetPoint (5);
    ASSERT_NEAR (point.m_weight, 1.0 / 6.0, TOLERANCE);
    ASSERT_NEAR (point.m_x,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_y,  xb, TOLERANCE);
    ASSERT_NEAR (point.m_z,  xc, TOLERANCE);
}